package top.jfunc.common.servlet;

import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.util.ContentCachingRequestWrapper;
import top.jfunc.common.http.base.MediaType;
import top.jfunc.common.http.base.Method;
import top.jfunc.common.utils.CharsetUtil;
import top.jfunc.common.utils.IpUtil;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.util.regex.Pattern;

/**
 * @author xiongshiyan
 */
public class RequestParamUtil {
	/**
	 * 获取请求中的body，并设置回去，因为流只能被读一次
	 */
	public static String getBody(HttpServletRequest httpServletRequest) throws IOException {
		if (httpServletRequest instanceof MultiReadHttpServletRequest) {
			return ((MultiReadHttpServletRequest) httpServletRequest).getBody();
		}
		if (httpServletRequest instanceof ContentCachingRequestWrapper) {
			return new String(((ContentCachingRequestWrapper) httpServletRequest).getContentAsByteArray());
		}

		// 把所有请求的数据保存下来
		InputStream stream = httpServletRequest.getInputStream();
		byte[] bs = new byte[stream.available()];
		stream.read(bs);
		// 重新设置EntityStream
		//ByteArrayInputStream bai = new ByteArrayInputStream(bs);
		// 为了后面的处理，因为流只能被读一次。
		//httpServletRequest.s(bai);

		return new String(bs, CharsetUtil.UTF_8);
	}

	public static String ip(HttpServletRequest requestContext) {
		return IpUtil.getClientIp(requestContext::getHeader, null);
	}
	public static HttpServletRequest currentRequest() {
		RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
		if(null == requestAttributes){
			return null;
		}
		if(requestAttributes instanceof ServletRequestAttributes){
			return ((ServletRequestAttributes)requestAttributes).getRequest();
		}
		return null;
	}
	public static HttpServletResponse currentResponse() {
		RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
		if(null == requestAttributes){
			return null;
		}
		if(requestAttributes instanceof ServletRequestAttributes){
			return ((ServletRequestAttributes)requestAttributes).getResponse();
		}
		return null;
	}

	/**
	 * 有开头的斜杠
	 */
	public static String requestUriSlash(HttpServletRequest httpServletRequest) {
		// /sample/test
		String servletPath = httpServletRequest.getServletPath();
		// /sample/test 或者 /sample/test/
		// 攻击者使用后者也可以映射到，某些根据uri匹配的规则就会失效
		if(!"/".equals(servletPath)){
			return regularization(servletPath);
		}
		return servletPath;
	}

	/**
	 * 没有开头的斜杠
	 */
	public static String requestUri(HttpServletRequest httpServletRequest) {
		// sample/test
		return requestUriSlash(httpServletRequest).substring(1);
	}
	public static String requestURI(HttpServletRequest httpServletRequest) {
		// /dzg-rest-query/sample/test
		String requestURI = httpServletRequest.getRequestURI();
		if(!"/".equals(requestURI)){
			return regularization(requestURI);
		}
		return requestURI;
	}

	/**
	 * 规整化，攻击者使用后者也可以映射到，某些根据uri匹配的规则就会失效
	 * @param src 原始路径
	 * @return 规整化后的路径
	 */
	private static String regularization(String src){
		if(src.endsWith("/")){
			String removedLast = src.substring(0, src.length() - 1);
			return regularization(removedLast);
		}
		return src;
	}

	/**
	 * 只允许字母、数字、斜杠、-、_和.【文件后缀】
	 */
	private static final Pattern NORMAL_URI_PATTERN = Pattern.compile("[^0-9a-zA-Z/.\\-_]");

	public static boolean containsIllegalChars(String uri){
		return NORMAL_URI_PATTERN.matcher(uri).find();
	}

	/**
	 * 判断是否是文件上传类型请求
	 */
	public static boolean isMultiPartRequest(HttpServletRequest httpServletRequest) {
		String contentType = httpServletRequest.getContentType();
		if(null == contentType){
			return false;
		}
		MediaType mediaType = MediaType.parse(contentType);
		return null != mediaType && MediaType.MULTIPART_FORM_DATA_STRING.equals(mediaType.withCharset((String) null).toString());
	}
	/**
	 * 判断是否是form类型请求
	 */
	public static boolean isFormRequest(HttpServletRequest httpServletRequest) {
		String contentType = httpServletRequest.getContentType();
		if(null == contentType){
			return false;
		}
		MediaType mediaType = MediaType.parse(contentType);
		return null != mediaType && MediaType.APPLICATION_FORM_DATA_STRING.equals(mediaType.withCharset((String) null).toString());
	}

	public static boolean isPost(HttpServletRequest httpServletRequest) {
		return Method.POST.name().equals(httpServletRequest.getMethod());
	}
	public static boolean isGet(HttpServletRequest httpServletRequest) {
		return Method.GET.name().equals(httpServletRequest.getMethod());
	}
}
